﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System.Windows;
using System.Windows.Controls;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Generic;

namespace Microsoft.WVB.UI
{
    public class WrapPanel : Panel
    {
        // Fields
        private bool _ignorePropertyChange;
        public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(WrapPanel), new PropertyMetadata((double)1.0 / (double)0.0, new PropertyChangedCallback(WrapPanel.OnItemHeightOrWidthPropertyChanged)));
        public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(WrapPanel), new PropertyMetadata((double)1.0 / (double)0.0, new PropertyChangedCallback(WrapPanel.OnItemHeightOrWidthPropertyChanged)));
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(WrapPanel), new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(WrapPanel.OnOrientationPropertyChanged)));

        // Methods
        private void ArrangeLine(int lineStart, int lineEnd, double? directDelta, double indirectOffset, double indirectGrowth)
        {
            double x = 0.0;
            Orientation orientation = this.Orientation;
            bool flag = orientation == Orientation.Horizontal;
            UIElementCollection children = base.Children;
            for (int i = lineStart; i < lineEnd; i++)
            {
                UIElement element = children[i];
                OrientedSize size = new OrientedSize(orientation, element.DesiredSize.Width, element.DesiredSize.Height);
                double width = directDelta.HasValue ? directDelta.Value : size.Direct;
                Rect finalRect = flag ? new Rect(x, indirectOffset, width, indirectGrowth) : new Rect(indirectOffset, x, indirectGrowth, width);
                element.Arrange(finalRect);
                x += width;
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            Orientation orientation = this.Orientation;
            OrientedSize size = new OrientedSize(orientation);
            OrientedSize size2 = new OrientedSize(orientation, finalSize.Width, finalSize.Height);
            double itemWidth = this.ItemWidth;
            double itemHeight = this.ItemHeight;
            bool flag = !itemWidth.IsNaN();
            bool flag2 = !itemHeight.IsNaN();
            double indirectOffset = 0.0;
            double? directDelta = (orientation == Orientation.Horizontal) ? (flag ? new double?(itemWidth) : null) : (flag2 ? new double?(itemHeight) : null);
            UIElementCollection children = base.Children;
            int count = children.Count;
            int lineStart = 0;
            for (int i = 0; i < count; i++)
            {
                UIElement element = children[i];
                OrientedSize size3 = new OrientedSize(orientation, flag ? itemWidth : element.DesiredSize.Width, flag2 ? itemHeight : element.DesiredSize.Height);
                if (NumericExtensions.IsGreaterThan(size.Direct + size3.Direct, size2.Direct))
                {
                    this.ArrangeLine(lineStart, i, directDelta, indirectOffset, size.Indirect);
                    indirectOffset += size.Indirect;
                    size = size3;
                    if (NumericExtensions.IsGreaterThan(size3.Direct, size2.Direct))
                    {
                        this.ArrangeLine(i, ++i, directDelta, indirectOffset, size3.Indirect);
                        indirectOffset += size.Indirect;
                        size = new OrientedSize(orientation);
                    }
                    lineStart = i;
                }
                else
                {
                    size.Direct += size3.Direct;
                    size.Indirect = Math.Max(size.Indirect, size3.Indirect);
                }
            }
            if (lineStart < count)
            {
                this.ArrangeLine(lineStart, count, directDelta, indirectOffset, size.Indirect);
            }
            return finalSize;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Orientation orientation = this.Orientation;
            OrientedSize size = new OrientedSize(orientation);
            OrientedSize size2 = new OrientedSize(orientation);
            OrientedSize size3 = new OrientedSize(orientation, availableSize.Width, availableSize.Height);
            double itemWidth = this.ItemWidth;
            double itemHeight = this.ItemHeight;
            bool flag = !itemWidth.IsNaN();
            bool flag2 = !itemHeight.IsNaN();
            Size size4 = new Size(flag ? itemWidth : availableSize.Width, flag2 ? itemHeight : availableSize.Height);
            foreach (UIElement element in base.Children)
            {
                element.Measure(size4);
                OrientedSize size5 = new OrientedSize(orientation, flag ? itemWidth : element.DesiredSize.Width, flag2 ? itemHeight : element.DesiredSize.Height);
                if (NumericExtensions.IsGreaterThan(size.Direct + size5.Direct, size3.Direct))
                {
                    size2.Direct = Math.Max(size.Direct, size2.Direct);
                    size2.Indirect += size.Indirect;
                    size = size5;
                    if (NumericExtensions.IsGreaterThan(size5.Direct, size3.Direct))
                    {
                        size2.Direct = Math.Max(size5.Direct, size2.Direct);
                        size2.Indirect += size5.Indirect;
                        size = new OrientedSize(orientation);
                    }
                }
                else
                {
                    size.Direct += size5.Direct;
                    size.Indirect = Math.Max(size.Indirect, size5.Indirect);
                }
            }
            size2.Direct = Math.Max(size.Direct, size2.Direct);
            size2.Indirect += size.Indirect;
            return new Size(size2.Width, size2.Height);
        }

        [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Almost always set from the CLR property.")]
        private static void OnItemHeightOrWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WrapPanel panel = (WrapPanel)d;
            double newValue = (double)e.NewValue;
            if (panel._ignorePropertyChange)
            {
                panel._ignorePropertyChange = false;
            }
            else
            {
                if (!newValue.IsNaN() && ((newValue <= 0.0) || double.IsPositiveInfinity(newValue)))
                {
                    panel._ignorePropertyChange = true;
                    panel.SetValue(e.Property, (double)e.OldValue);
                    throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Microsoft.WVB.UI.Resources.WrapPanel_OnItemHeightOrWidthPropertyChanged_InvalidValue, new object[] { newValue }), "value");
                }
                panel.InvalidateMeasure();
            }
        }

        [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Almost always set from the CLR property.")]
        private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WrapPanel panel = (WrapPanel)d;
            Orientation newValue = (Orientation)e.NewValue;
            if (panel._ignorePropertyChange)
            {
                panel._ignorePropertyChange = false;
            }
            else
            {
                if ((newValue != Orientation.Horizontal) && (newValue != Orientation.Vertical))
                {
                    panel._ignorePropertyChange = true;
                    panel.SetValue(OrientationProperty, (Orientation)e.OldValue);
                    throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Microsoft.WVB.UI.Resources.WrapPanel_OnOrientationPropertyChanged_InvalidValue, new object[] { newValue }), "value");
                }
                panel.InvalidateMeasure();
            }
        }

        // Properties
        [TypeConverter(typeof(LengthConverter))]
        public double ItemHeight
        {
            get
            {
                return (double)base.GetValue(ItemHeightProperty);
            }
            set
            {
                base.SetValue(ItemHeightProperty, value);
            }
        }

        [TypeConverter(typeof(LengthConverter))]
        public double ItemWidth
        {
            get
            {
                return (double)base.GetValue(ItemWidthProperty);
            }
            set
            {
                base.SetValue(ItemWidthProperty, value);
            }
        }

        public Orientation Orientation
        {
            get
            {
                return (Orientation)base.GetValue(OrientationProperty);
            }
            set
            {
                base.SetValue(OrientationProperty, value);
            }
        }
    }

    internal static class NumericExtensions
    {
        // Methods
        public static bool AreClose(double left, double right)
        {
            if (left == right)
            {
                return true;
            }
            double num = ((Math.Abs(left) + Math.Abs(right)) + 10.0) * 2.2204460492503131E-16;
            double num2 = left - right;
            return ((-num < num2) && (num > num2));
        }

        public static bool IsGreaterThan(double left, double right)
        {
            return ((left > right) && !AreClose(left, right));
        }

        public static bool IsLessThanOrClose(double left, double right)
        {
            if (left >= right)
            {
                return AreClose(left, right);
            }
            return true;
        }

        public static bool IsNaN(this double value)
        {
            NanUnion union2 = new NanUnion();
            union2.FloatingValue = value;
            NanUnion union = union2;
            ulong num = union.IntegerValue & 18442240474082181120L;
            if ((num != 0x7ff0000000000000L) && (num != 18442240474082181120L))
            {
                return false;
            }
            ulong num2 = union.IntegerValue & ((ulong)0xfffffffffffffL);
            return (num2 != 0L);
        }

        public static bool IsZero(this double value)
        {
            return (Math.Abs(value) < 2.2204460492503131E-15);
        }

        // Nested Types
        [StructLayout(LayoutKind.Explicit)]
        private struct NanUnion
        {
            // Fields
            [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "It is accessed through the other member of the union"), FieldOffset(0)]
            internal double FloatingValue;
            [FieldOffset(0)]
            internal ulong IntegerValue;
        }
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct OrientedSize
    {
        private Orientation _orientation;
        private double _direct;
        private double _indirect;
        public Orientation Orientation
        {
            get
            {
                return this._orientation;
            }
        }
        public double Direct
        {
            get
            {
                return this._direct;
            }
            set
            {
                this._direct = value;
            }
        }
        public double Indirect
        {
            get
            {
                return this._indirect;
            }
            set
            {
                this._indirect = value;
            }
        }
        public double Width
        {
            get
            {
                if (this.Orientation != Orientation.Horizontal)
                {
                    return this.Indirect;
                }
                return this.Direct;
            }
            set
            {
                if (this.Orientation == Orientation.Horizontal)
                {
                    this.Direct = value;
                }
                else
                {
                    this.Indirect = value;
                }
            }
        }
        public double Height
        {
            get
            {
                if (this.Orientation == Orientation.Horizontal)
                {
                    return this.Indirect;
                }
                return this.Direct;
            }
            set
            {
                if (this.Orientation != Orientation.Horizontal)
                {
                    this.Direct = value;
                }
                else
                {
                    this.Indirect = value;
                }
            }
        }
        public OrientedSize(Orientation orientation)
            : this(orientation, 0.0, 0.0)
        {
        }

        public OrientedSize(Orientation orientation, double width, double height)
        {
            this._orientation = orientation;
            this._direct = 0.0;
            this._indirect = 0.0;
            this.Width = width;
            this.Height = height;
        }
    }

    public class LengthConverter : TypeConverter
    {
        // Fields
        private static Dictionary<string, double> UnitToPixelConversions;

        // Methods
        static LengthConverter()
        {
            Dictionary<string, double> dictionary = new Dictionary<string, double>();
            dictionary.Add("px", 1.0);
            dictionary.Add("in", 96.0);
            dictionary.Add("cm", 37.795275590551178);
            dictionary.Add("pt", 1.3333333333333333);
            UnitToPixelConversions = dictionary;
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            switch (Type.GetTypeCode(sourceType))
            {
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                case TypeCode.String:
                    return true;
            }
            return false;
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return TypeConverters.CanConvertTo<double>(destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value == null)
            {
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.TypeConverters_ConvertFrom_CannotConvertFromType, new object[] { base.GetType().Name, "null" }));
            }
            string strA = value as string;
            if (strA != null)
            {
                if (string.Compare(strA, "Auto", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return (double)1.0 / (double)0.0;
                }
                string str3 = strA;
                double num = 1.0;
                foreach (KeyValuePair<string, double> pair in UnitToPixelConversions)
                {
                    if (str3.EndsWith(pair.Key, StringComparison.Ordinal))
                    {
                        num = pair.Value;
                        str3 = strA.Substring(0, str3.Length - pair.Key.Length);
                        break;
                    }
                }
                try
                {
                    return (num * Convert.ToDouble(str3, culture));
                }
                catch (FormatException)
                {
                    throw new FormatException(string.Format(CultureInfo.CurrentCulture, Resources.TypeConverters_Convert_CannotConvert, new object[] { base.GetType().Name, strA, typeof(double).Name }));
                }
            }
            return Convert.ToDouble(value, culture);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (value is double)
            {
                double num = (double)value;
                if (destinationType == typeof(string))
                {
                    if (!num.IsNaN())
                    {
                        return Convert.ToString(num, culture);
                    }
                    return "Auto";
                }
            }
            return TypeConverters.ConvertTo(this, value, destinationType);
        }
    }

    internal static class TypeConverters
    {
        // Methods
        internal static bool CanConvertFrom<T>(Type sourceType)
        {
            if (sourceType == null)
            {
                throw new ArgumentNullException("sourceType");
            }
            if (sourceType != typeof(string))
            {
                return typeof(T).IsAssignableFrom(sourceType);
            }
            return true;
        }

        internal static bool CanConvertTo<T>(Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
            if (destinationType != typeof(string))
            {
                return destinationType.IsAssignableFrom(typeof(T));
            }
            return true;
        }

        internal static object ConvertFrom<T>(TypeConverter converter, object value)
        {
            if (!(value is T))
            {
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.TypeConverters_ConvertFrom_CannotConvertFromType, new object[] { converter.GetType().Name, (value != null) ? value.GetType().FullName : "(null)" }));
            }
            return value;
        }

        internal static object ConvertTo(TypeConverter converter, object value, Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
            if ((value == null) && !destinationType.IsValueType)
            {
                return null;
            }
            if ((value == null) || !destinationType.IsAssignableFrom(value.GetType()))
            {
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.TypeConverters_Convert_CannotConvert, new object[] { converter.GetType().Name, (value != null) ? value.GetType().FullName : "(null)", destinationType.GetType().Name }));
            }
            return value;
        }
    }

}
